package edu.washington.ling.syntric.proc;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;

import edu.washington.ling.syntric.consistency.*;
import edu.washington.ling.syntric.io.ExampleDoc;
import edu.washington.ling.syntric.io.ExampleDocReader;
import edu.washington.ling.syntric.io.ExampleDocWriter;
import edu.washington.ling.syntric.io.Example;
import edu.washington.ling.syntric.io.TreeReader;
import edu.washington.ling.syntric.io.TreeWriter;
import edu.washington.ling.syntric.struct.error.PrintingExceptionHandler;
import edu.washington.ling.syntric.struct.error.UnreadableRepresentationException;
import edu.washington.ling.syntric.struct.tree.Tree;

public class ApplyConsistencyRules {
	
	private static ApplyConsistencyRulesOptions opts = new ApplyConsistencyRulesOptions();
	private static PrintingExceptionHandler pHandler = new PrintingExceptionHandler();
	
	public static List<ConsistencyRule> initializeRules(OrderModule orderModule) {
		List<ConsistencyRule> rules = new LinkedList<ConsistencyRule>();
		try {
			rules.add(new RelationMappingRule());
			rules.add(new CausativeRule());
			rules.add(new RelativeClauseRule());
			rules.add(new UnaccusativeRule());
			rules.add(new PassiveRule());
			rules.add(new SupportVerbRule());
			rules.add(new SmallClauseRule());
			rules.add(new LocalMovementRule(orderModule));
			rules.add(new LongDistanceMovementRule());
		}
		catch(IOException e) {
			pHandler.handle(e, "DS consistency conversion failed: could not initialize the rules");
			e.printStackTrace();
			System.exit(-1);
		}
		return rules;
	}

	public static void applyConsistencyRules(Tree ds, List<ConsistencyRule> rules) {
		for (ConsistencyRule rule: rules) {
			rule.apply(ds);
		}
	}

	private static void applyConsistencyRulesToInputFile(List<ConsistencyRule> rules, OrderModule orderModule){
		int numExamples = 0;
		int numWithDS = 0;
		int numDSConstCreated = 0;
		try {
			ExampleDocReader exfr = ExampleDocReader.newReader(opts.inputFilePath, "xml");
			ExampleDoc exf = exfr.read();
			ExampleDocWriter exfw = ExampleDocWriter.newWriter(opts.outputFilePath, "xml");
			TreeReader trr = TreeReader.newReader(opts.dsTreeFormat);
			TreeWriter trw = TreeWriter.newWriter(opts.dsTreeFormat);
			Example exr = null;
			while ((exr = exf.getNextExample()) != null) {
				numExamples++;
				if (exr.hasTreeRep("DS+PB")) {
					try {
						numWithDS++;
						Tree ds = trr.readTree(exr.getTreeRep("DS+PB"));
						ds.setLayer("DS-Const");
						applyConsistencyRules(ds, rules);
						ConsistencyUtils.attachECs(ds, orderModule);
						exr.addTreeRep(trw.writeTree(ds));
						numDSConstCreated++;
					}
					catch (UnreadableRepresentationException e) {
						String errStr = String.format("Could not process representation '%s'", exr.getID());
						pHandler.handle(e, errStr);
					}
				}
				else if (exr.hasTreeRep("DS")) {
					try {
						numWithDS++;
						Tree ds = trr.readTree(exr.getTreeRep("DS"));
						ds.setLayer("DS-Const");
						applyConsistencyRules(ds, rules);
						ConsistencyUtils.attachECs(ds, orderModule);
						exr.addTreeRep(trw.writeTree(ds));
						numDSConstCreated++;
					}
					catch (UnreadableRepresentationException e) {
						String errStr = String.format("Could not process representation '%s'", exr.getID());
						pHandler.handle(e, errStr);
					}
				}
				
				exfw.writeExample(exr);
			}
			exfw.close();
		} 
		catch(Exception e) {
			pHandler.handle(e, "Apply DS consistency rules failed.", System.out);
			e.printStackTrace(System.out);
			System.exit(-1);
		}
		System.out.println("Apply DS consistency rules was successful.");
		System.out.println(String.format("%d/%d DS const trees were created", numDSConstCreated, numWithDS));
		System.out.println(String.format("Processed %d total examples", numExamples));
	}
	

	public static void main(String[] args) {
		CmdLineParser parser = new CmdLineParser(opts);
		try {
			parser.parseArgument(args);
			OrderModule orderModule = new OrderModule();
			List<ConsistencyRule> rules = initializeRules(orderModule);
			applyConsistencyRulesToInputFile(rules, orderModule);
		} 
		
		catch(CmdLineException e) {
			System.out.println(e.getMessage());
			System.out.print("Usage: ApplyConsistencyRules");
			parser.printSingleLineUsage(System.out);
			System.out.println();
			parser.printUsage(System.out);
			System.exit(-1);
		}
	}
}
